// 《围棋》作者版权所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package escape

import (
	"cmd/compile/internal/base"
	"math"
	"strings"
)

const numEscResults = 7

// 泄漏表示一组从参数
// 到堆或其任何函数（第一个numescurts）
// 结果参数的赋值流。
type leaks [1 + numEscResults]uint8

// Empty报告l是否为空集（即没有赋值流）。
func (l leaks) Empty() bool { return l == leaks{} }

// Heap返回从l 
// 到堆的任何赋值流的最小deref计数。如果不存在这样的流，Heap将返回-1。
func (l leaks) Heap() int { return l.get(0) }

// Result返回从
// l到其函数的第i个结果参数的任何赋值流的最小deref计数。如果不存在这样的流，
// 结果返回-1。
func (l leaks) Result(i int) int { return l.get(1 + i) }

// AddHeap将分配流从l添加到堆中。
func (l *leaks) AddHeap(derefs int) { l.add(0, derefs) }

// AddResult将赋值流从l添加到其函数的第i个
// result参数。
func (l *leaks) AddResult(i, derefs int) { l.add(1+i, derefs) }

func (l *leaks) setResult(i, derefs int) { l.set(1+i, derefs) }

func (l leaks) get(i int) int { return int(l[i]) - 1 }

func (l *leaks) add(i, derefs int) {
	if old := l.get(i); old < 0 || derefs < old {
		l.set(i, derefs)
	}
}

func (l *leaks) set(i, derefs int) {
	v := derefs + 1
	if v < 0 {
		base.Fatalf("invalid derefs count: %v", derefs)
	}
	if v > math.MaxUint8 {
		v = math.MaxUint8
	}

	l[i] = uint8(v)
}

// 优化删除长度等于或
// 长于最短堆流路径的结果流路径。
func (l *leaks) Optimize() {
	// 如果我们有一条到堆的路径，那么在其他地方保持相同或更长的路径是没有用的。
	if x := l.Heap(); x >= 0 {
		for i := 0; i < numEscResults; i++ {
			if l.Result(i) >= x {
				l.setResult(i, -1)
			}
		}
	}
}

var leakTagCache = map[leaks]string{}

// Encode将l转换为二进制字符串以导出数据。
func (l leaks) Encode() string {
	if l.Heap() == 0 {
		// 空间优化：空字符串在导出数据时编码效率更高。
		return ""
	}
	if s, ok := leakTagCache[l]; ok {
		return s
	}

	n := len(l)
	for n > 0 && l[n-1] == 0 {
		n--
	}
	s := "esc:" + string(l[:n])
	leakTagCache[l] = s
	return s
}

// parseLeaks解析表示泄漏的二进制字符串
func parseLeaks(s string) leaks {
	var l leaks
	if !strings.HasPrefix(s, "esc:") {
		l.AddHeap(0)
		return l
	}
	copy(l[:], s[4:])
	return l
}
